{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Deep Learning"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import tensorflow as tf\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "pd.set_option(\"display.max_rows\",15)\n",
    "%matplotlib inline\n",
    "\n",
    "sess = tf.InteractiveSession()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "tf.reset_default_graph()\n",
    "\n",
    "input_dim = 122\n",
    "classes = 2\n",
    "hidden_encoder_dim = 80\n",
    "\n",
    "latent_dim = 10\n",
    "\n",
    "hidden_decoder_dim = 80\n",
    "\n",
    "lam = 0.01\n",
    "\n",
    "def weight_variable(shape):\n",
    "    initial = tf.truncated_normal(shape, stddev=0.001)\n",
    "    return tf.Variable(initial)\n",
    "\n",
    "def bias_variable(shape):\n",
    "    initial = tf.constant(0.01, shape=shape)\n",
    "    return tf.Variable(initial)\n",
    "\n",
    "l2_loss = tf.constant(0.001)\n",
    "#learning_rate = tf.Variable(initial_value=0.001)\n",
    "\n",
    "with tf.variable_scope(\"Input\"):\n",
    "    x = tf.placeholder(\"float\", shape=[None, input_dim])\n",
    "    y_ = tf.placeholder(\"float\", shape=[None, classes])\n",
    "    \n",
    "    keep_prob = tf.placeholder(\"float\")\n",
    "\n",
    "with tf.variable_scope(\"Layer_Encoder\"):\n",
    "    W_encoder_input_hidden = weight_variable([input_dim,hidden_encoder_dim])\n",
    "    b_encoder_input_hidden = bias_variable([hidden_encoder_dim])\n",
    "    l2_loss += tf.nn.l2_loss(W_encoder_input_hidden)\n",
    "\n",
    "    # Hidden layer encoder\n",
    "    hidden_encoder = tf.nn.relu(tf.matmul(x, W_encoder_input_hidden) + b_encoder_input_hidden)\n",
    "    tf.summary.histogram(\"Weights_Encoder\", W_encoder_input_hidden)\n",
    "    hidden_encoder = tf.nn.dropout(hidden_encoder, keep_prob=keep_prob)\n",
    "\n",
    "with tf.variable_scope(\"Layer_Mean\"):\n",
    "    W_encoder_hidden_mu = weight_variable([hidden_encoder_dim,latent_dim])\n",
    "    b_encoder_hidden_mu = bias_variable([latent_dim])\n",
    "    l2_loss += tf.nn.l2_loss(W_encoder_hidden_mu)\n",
    "\n",
    "    # Mu encoder\n",
    "    mu_encoder = tf.matmul(hidden_encoder, W_encoder_hidden_mu) + b_encoder_hidden_mu\n",
    "    tf.summary.histogram(\"Weights_Mean\", W_encoder_hidden_mu)\n",
    "\n",
    "with tf.variable_scope(\"Layer_Variance\"):\n",
    "    W_encoder_hidden_logvar = weight_variable([hidden_encoder_dim,latent_dim])\n",
    "    b_encoder_hidden_logvar = bias_variable([latent_dim])\n",
    "    l2_loss += tf.nn.l2_loss(W_encoder_hidden_logvar)\n",
    "\n",
    "    # Sigma encoder\n",
    "    logvar_encoder = tf.matmul(hidden_encoder, W_encoder_hidden_logvar) + b_encoder_hidden_logvar\n",
    "    tf.summary.histogram(\"Weights_Variance\", W_encoder_hidden_logvar)\n",
    "\n",
    "with tf.variable_scope(\"Sampling_Distribution\"):\n",
    "    # Sample epsilon\n",
    "    epsilon = tf.random_normal(tf.shape(logvar_encoder), name='epsilon')\n",
    "\n",
    "    # Sample latent variable\n",
    "    std_encoder = tf.exp(0.5 * logvar_encoder)\n",
    "    z = mu_encoder + tf.multiply(std_encoder, epsilon)\n",
    "    tf.summary.histogram(\"Sample_Distribution\", z)\n",
    "    \n",
    "with tf.variable_scope(\"Layer_Decoder\"):\n",
    "    W_decoder_z_hidden = weight_variable([latent_dim,hidden_decoder_dim])\n",
    "    b_decoder_z_hidden = bias_variable([hidden_decoder_dim])\n",
    "    l2_loss += tf.nn.l2_loss(W_decoder_z_hidden)\n",
    "\n",
    "    # Hidden layer decoder\n",
    "    hidden_decoder = tf.nn.relu(tf.matmul(z, W_decoder_z_hidden) + b_decoder_z_hidden)\n",
    "    hidden_decoder = tf.nn.dropout(hidden_decoder, keep_prob=keep_prob)\n",
    "    tf.summary.histogram(\"Weights_Decoder\", W_decoder_z_hidden)\n",
    "\n",
    "with tf.variable_scope(\"Layer_Reconstruction\"):\n",
    "    W_decoder_hidden_reconstruction = weight_variable([hidden_decoder_dim, input_dim])\n",
    "    b_decoder_hidden_reconstruction = bias_variable([input_dim])\n",
    "    l2_loss += tf.nn.l2_loss(W_decoder_hidden_reconstruction)\n",
    "\n",
    "    x_hat = tf.matmul(hidden_decoder, W_decoder_hidden_reconstruction) + b_decoder_hidden_reconstruction\n",
    "    tf.summary.histogram(\"Weights_Reconstruction\", W_decoder_hidden_reconstruction)\n",
    "\n",
    "with tf.variable_scope(\"Layer_Dense_Hidden\"):\n",
    "    hidden_output = tf.layers.dense(z,latent_dim, activation=tf.nn.relu)\n",
    "\n",
    "with tf.variable_scope(\"Layer_Dense_Softmax\"):\n",
    "    y = tf.layers.dense(z, classes, activation=tf.nn.softmax)\n",
    "    \n",
    "with tf.variable_scope(\"Loss\"):\n",
    "    BCE = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=x_hat, labels=x), reduction_indices=1)\n",
    "    KLD = -0.5 * tf.reduce_mean(1 + logvar_encoder - tf.pow(mu_encoder, 2) - tf.exp(logvar_encoder), reduction_indices=1)\n",
    "    loss_softmax = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels = y_, logits = y))\n",
    "    \n",
    "    loss_vae = tf.reduce_mean(BCE + KLD)\n",
    "    \n",
    "    loss_regularized_vae = tf.abs(loss_vae + lam * l2_loss, name = \"Regularized_loss\")\n",
    "    \n",
    "    \n",
    "    pred = tf.argmax(y, 1)\n",
    "    actual = tf.argmax(y_, 1)\n",
    "    \n",
    "    #tf.summary.scalar(\"BCE\", BCE)\n",
    "    #tf.summary.scalar(\"KLD\", KLD)\n",
    "    #tf.summary.scalar(\"Softmax_loss\", softmax_loss)\n",
    "    \n",
    "    tf.summary.scalar(\"loss\", loss_regularized_vae)\n",
    "    \n",
    "with tf.variable_scope(\"Optimizer_VAE\"):\n",
    "    learning_rate=0.001\n",
    "    grad_clip=5\n",
    "    tvars = tf.trainable_variables()\n",
    "    grads, _ = tf.clip_by_global_norm(tf.gradients(loss_regularized_vae, tvars), grad_clip)\n",
    "    train_op = tf.train.AdamOptimizer(learning_rate)\n",
    "    optimizer_vae = train_op.apply_gradients(zip(grads, tvars))\n",
    "\n",
    "with tf.variable_scope(\"Optimizer_Softmax\"):\n",
    "    optimizer_softmax = tf.train.AdamOptimizer(0.0001).minimize(loss_softmax)\n",
    "\n",
    "correct_prediction = tf.equal(tf.argmax(y_, 1), tf.argmax(y, 1))\n",
    "tf_accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32), name = \"Accuracy\")\n",
    "\n",
    "# add op for merging summary\n",
    "summary_op = tf.summary.merge_all()\n",
    "\n",
    "# add Saver ops\n",
    "# saver = tf.train.Saver()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "kdd_train_2labels = pd.read_pickle(\"dataset/kdd_train_2labels.pkl\")\n",
    "kdd_test_2labels = pd.read_pickle(\"dataset/kdd_test_2labels.pkl\")\n",
    "\n",
    "\n",
    "output_columns_2labels = ['is_Attack','is_Normal']\n",
    "\n",
    "from sklearn import model_selection as ms\n",
    "from sklearn import preprocessing as pp\n",
    "\n",
    "x_input = kdd_train_2labels.drop(output_columns_2labels, axis = 1)\n",
    "y_output = kdd_train_2labels.loc[:,output_columns_2labels]\n",
    "\n",
    "ss = pp.StandardScaler()\n",
    "\n",
    "x_input = ss.fit_transform(x_input)\n",
    "\n",
    "x_test = kdd_test_2labels.drop(output_columns_2labels, axis = 1)\n",
    "y_test = kdd_test_2labels.loc[:,output_columns_2labels]\n",
    "\n",
    "x_test = ss.transform(x_test)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Step 0 | Training Loss: 0.4107\n",
      "Step 2 | Training Loss: 0.0292\n",
      "Step 4 | Training Loss: 0.1480\n",
      "Step 6 | Training Loss: 0.0547\n",
      "Step 8 | Training Loss: 0.0545\n",
      "Step 10 | Training Loss: 0.0782\n",
      "Step 12 | Training Loss: 0.0061\n",
      "Step 14 | Training Loss: 0.0097\n",
      "Step 16 | Training Loss: 0.0364\n",
      "Step 18 | Training Loss: 0.0030\n",
      "Step 20 | Training Loss: 0.0188\n",
      "Step 22 | Training Loss: 0.0372\n",
      "Step 24 | Training Loss: 0.0230\n",
      "Step 26 | Training Loss: 0.0009\n",
      "Step 28 | Training Loss: 0.0099\n",
      "Step 30 | Training Loss: 0.0154\n",
      "Step 32 | Training Loss: 0.0094\n",
      "Step 34 | Training Loss: 0.0316\n",
      "Step 36 | Training Loss: 0.0223\n",
      "Step 38 | Training Loss: 0.0602\n",
      "Step 0 | Training Loss: 0.7568 | Validation Accuracy: 0.4649\n",
      "Step 2 | Training Loss: 0.5088 | Validation Accuracy: 0.8083\n",
      "Step 4 | Training Loss: 0.4192 | Validation Accuracy: 0.9272\n",
      "Step 6 | Training Loss: 0.3831 | Validation Accuracy: 0.9501\n",
      "Step 8 | Training Loss: 0.3641 | Validation Accuracy: 0.9633\n",
      "Step 10 | Training Loss: 0.3556 | Validation Accuracy: 0.9695\n",
      "Step 12 | Training Loss: 0.3479 | Validation Accuracy: 0.9740\n",
      "Step 14 | Training Loss: 0.3407 | Validation Accuracy: 0.9751\n",
      "Step 16 | Training Loss: 0.3401 | Validation Accuracy: 0.9757\n",
      "Step 18 | Training Loss: 0.3363 | Validation Accuracy: 0.9740\n",
      "Step 20 | Training Loss: 0.3489 | Validation Accuracy: 0.9748\n",
      "Step 22 | Training Loss: 0.3376 | Validation Accuracy: 0.9756\n",
      "Step 24 | Training Loss: 0.3332 | Validation Accuracy: 0.9750\n",
      "Step 26 | Training Loss: 0.3405 | Validation Accuracy: 0.9782\n",
      "Step 28 | Training Loss: 0.3358 | Validation Accuracy: 0.9765\n",
      "Step 30 | Training Loss: 0.3378 | Validation Accuracy: 0.9780\n",
      "Step 32 | Training Loss: 0.3348 | Validation Accuracy: 0.9767\n",
      "Step 34 | Training Loss: 0.3428 | Validation Accuracy: 0.9781\n",
      "Step 36 | Training Loss: 0.3360 | Validation Accuracy: 0.9781\n",
      "Step 38 | Training Loss: 0.3417 | Validation Accuracy: 0.9779\n",
      "Accuracy on Test data: 0.7595369219779968\n"
     ]
    }
   ],
   "source": [
    "epochs = 40\n",
    "batch_iterations = 100\n",
    "\n",
    "\n",
    "\n",
    "with tf.Session() as sess:\n",
    "    summary_writer_train = tf.summary.FileWriter('./logs/kdd/VAE/training', graph=sess.graph)\n",
    "    summary_writer_valid = tf.summary.FileWriter('./logs/kdd/VAE/validation')\n",
    "\n",
    "    sess.run(tf.global_variables_initializer())\n",
    "\n",
    "    for epoch in range(0, epochs):\n",
    "        x_train, x_valid, y_train, y_valid = ms.train_test_split(x_input, \n",
    "                                                                  y_output.values, \n",
    "                                                                  test_size=0.2)\n",
    "        #x_valid, x_test, y_valid, y_test = ms.train_test_split(x_valid, y_valid, test_size = 0.4)\n",
    "        batch_indices = np.array_split(np.arange(x_train.shape[0]), batch_iterations)\n",
    "        \n",
    "        for i in batch_indices:\n",
    "            _, train_loss, summary_str = sess.run([optimizer_vae, loss_regularized_vae, summary_op],\n",
    "                                                  feed_dict={x: x_train[i,:], y_: y_train[i,:], keep_prob:0.6})\n",
    "\n",
    "        if epoch % 2 == 0:\n",
    "            print(\"Step {} | Training Loss: {:.4f}\".format(epoch, train_loss))\n",
    "        \n",
    "    for epoch in range(0, epochs):\n",
    "        x_train, x_valid, y_train, y_valid = ms.train_test_split(x_input, \n",
    "                                                                  y_output.values, \n",
    "                                                                  test_size=0.2)\n",
    "        #x_valid, x_test, y_valid, y_test = ms.train_test_split(x_valid, y_valid, test_size = 0.4)\n",
    "        batch_indices = np.array_split(np.arange(x_train.shape[0]), batch_iterations)\n",
    "        \n",
    "        for i in batch_indices:\n",
    "            _, train_loss, summary_str = sess.run([optimizer_softmax, loss_softmax, summary_op],\n",
    "                                                  feed_dict={x: x_train[i,:], y_: y_train[i,:], keep_prob:0.6})\n",
    "        \n",
    "        accuracy, summary_str = sess.run([tf_accuracy, summary_op], \n",
    "                                              feed_dict={x: x_valid, y_:y_valid, keep_prob:1})\n",
    "        summary_writer_valid.add_summary(summary_str, epoch)\n",
    "            \n",
    "        if epoch % 2 == 0:\n",
    "            print(\"Step {} | Training Loss: {:.4f} | Validation Accuracy: {:.4f}\".format(epoch, train_loss, accuracy))\n",
    "            \n",
    "            \n",
    "            \n",
    "    accuracy, pred_value, actual_value = sess.run([tf_accuracy, pred, actual], feed_dict={x: x_test, y_:y_test, keep_prob:1})\n",
    "    \n",
    "    print(\"Accuracy on Test data: {}\".format(accuracy))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import itertools\n",
    "\n",
    "def plot_confusion_matrix(cm, classes,\n",
    "                          normalize=False,\n",
    "                          title='Confusion matrix',\n",
    "                          cmap=plt.cm.Blues):\n",
    "    \"\"\"\n",
    "    This function prints and plots the confusion matrix.\n",
    "    Normalization can be applied by setting `normalize=True`.\n",
    "    \"\"\"\n",
    "    np.set_printoptions(precision=4)\n",
    "\n",
    "    plt.imshow(cm, interpolation='nearest', cmap=cmap)\n",
    "    plt.title(title)\n",
    "    plt.colorbar()\n",
    "    tick_marks = np.arange(len(classes))\n",
    "    plt.xticks(tick_marks, classes, rotation=45)\n",
    "    plt.yticks(tick_marks, classes)\n",
    "\n",
    "    if normalize:\n",
    "        cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]\n",
    "        print(\"Normalized confusion matrix\")\n",
    "    else:\n",
    "        print('Confusion matrix, without normalization')\n",
    "\n",
    "    print(cm)\n",
    "\n",
    "    thresh = cm.max() / 2.\n",
    "    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):\n",
    "        plt.text(j, i, cm[i, j].round(4),\n",
    "                 horizontalalignment=\"center\",\n",
    "                 color=\"white\" if cm[i, j] > thresh else \"black\")\n",
    "\n",
    "    plt.tight_layout()\n",
    "    plt.ylabel('True label')\n",
    "    plt.xlabel('Predicted label')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Normalized confusion matrix\n",
      "[[ 0.6345  0.3655]\n",
      " [ 0.0753  0.9247]]\n"
     ]
    },
    {
     "data": {
      "image/png": "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\ngg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f16046559b0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from sklearn.metrics import confusion_matrix\n",
    "cm_2labels = confusion_matrix(y_pred = pred_value, y_true = actual_value)\n",
    "plt.figure(figsize=[6,6])\n",
    "plot_confusion_matrix(cm_2labels, output_columns_2labels, normalize = True)"
   ]
  }
 ],
 "metadata": {
  "_draft": {
   "nbviewer_url": "https://gist.github.com/441dbeee083527e615728d6d3057ba04"
  },
  "gist": {
   "data": {
    "description": "With Truth Table: Getting 90% accuracy with KDDTest+",
    "public": false
   },
   "id": "441dbeee083527e615728d6d3057ba04"
  },
  "kernelspec": {
   "display_name": "Python [conda env:p3]",
   "language": "python",
   "name": "conda-env-p3-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
